package com.mgy.example.service.stock;

import com.mgy.example.annotation.MySqlLock;
import com.mgy.example.annotation.RedisLock;
import com.mgy.example.annotation.ZooKeeperLock;
import com.mgy.example.dao.mapper.stock.IStockDao;
import com.mgy.example.domain.stock.Stock;
import com.mgy.example.query.stock.StockQuery;
import com.mgy.example.service.common.lock.MySqlLockService;
import com.mgy.example.service.common.lock.RedisLockService;
import com.mgy.example.service.common.lock.ZkLockService;
import com.mgy.example.service.common.lock.ZkMutexLock;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.SQLException;
import java.util.List;
import java.util.UUID;

/**
 * 测试
 */
@Service
public class StockService {
    @Autowired
    private IStockDao stockDao;
    @Autowired
    private MySqlLockService lockService;
    @Autowired
    private RedisLockService redisLockService;
    @Autowired
    private ZkLockService zkLockService;
    @Autowired
    private CuratorFramework curatorFramework;
    @Autowired
    private Redisson redissonClient;


    /**
     * 插入一条记录
     *
     * @param stock
     * @return
     */
    public void add(Stock stock) throws SQLException {
        stockDao.add(stock);
    }

    /**
     * 根据主键删除记录
     *
     * @param id
     * @throws SQLException
     */
    public void deleteByKey(Long id) throws SQLException {
        stockDao.deleteByKey(id);
    }

    /**
     * 根据多个主键删除
     *
     * @param keys
     * @throws SQLException
     */
    public void deleteByKeys(List<Long> keys) throws SQLException {
        stockDao.deleteByKeys(keys);
    }

    /**
     * 根据主键查询记录
     *
     * @param id
     * @return
     * @throws SQLException
     */
    public Stock getByKey(Long id) throws SQLException {
        return stockDao.getByKey(id);
    }

    public Stock getOne(StockQuery stockQuery) {
        return stockDao.getOne(stockQuery);
    }


    /**
     * 无锁测试
     */
    public void updateByKey(Stock stock) throws Exception {
        Stock stock1 = stockDao.getByKey(stock.getId());
        if (stock1 == null) {
            System.out.println("商品不存在,id=" + stock.getId());
        }
        System.out.println(" 当前库存：num=" + stock1.getNum());

        stock.setNum(stock1.getNum() - 1);
        stockDao.updateByKey(stock);
    }


    /**
     * mysql 锁
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateByKey1(Stock stock) throws Exception {
        try {
            lockService.lock(stock.getId().toString());
            Stock stock1 = stockDao.getByKey(stock.getId());
            if (stock1 == null) {
                System.out.println("商品不存在,id=" + stock.getId());
            }
            System.out.println("当前库存：num=" + stock1.getNum());

            stock.setNum(stock1.getNum() - 1);
            stockDao.updateByKey(stock);
        } finally {
            lockService.unlock(stock.getId().toString());
        }
    }

    /**
     * redis 锁
     */
    public void updateByKey2(Stock stock) {
        String key = stock.getId() + "";
        String value = UUID.randomUUID().toString();
        try {
            redisLockService.tryLock(key, value);
            Stock stock1 = stockDao.getByKey(stock.getId());
            if (stock1 == null) {
                System.out.println("商品不存在,id=" + stock.getId());
            }
            System.out.println("当前库存：num=" + stock1.getNum());

            stock.setNum(stock1.getNum() - 1);
            stockDao.updateByKey(stock);
        } catch (Exception e) {
            System.out.println("加锁失败：" + e.getMessage());
        } finally {
            redisLockService.unlock(key, value);
        }
    }

    /**
     * redis 锁
     */
    public void updateByKey22(Stock stock) {
        String key = stock.getId() + "";
        String value = UUID.randomUUID().toString();
        try {
            redisLockService.tryLockNew(key, value);
            Stock stock1 = stockDao.getByKey(stock.getId());
            if (stock1 == null) {
                System.out.println("商品不存在,id=" + stock.getId());
            }
            System.out.println("当前库存：num=" + stock1.getNum());

            stock.setNum(stock1.getNum() - 1);
            stockDao.updateByKey(stock);
        } catch (Exception e) {
            System.out.println("加锁失败：" + e.getMessage());
        } finally {
            redisLockService.unlockNew(key, value);
        }
    }

    /**
     * curator 锁
     */
    public void updateByKey3(Stock stock) throws Exception {
        InterProcessMutex mutex = null;
        try {
            mutex = zkLockService.tryLock();
            Stock stock1 = stockDao.getByKey(stock.getId());
            if (stock1 == null) {
                System.out.println("商品不存在,id=" + stock.getId());
            }
            System.out.println("当前库存：num=" + stock1.getNum());

            stock.setNum(stock1.getNum() - 1);
            stockDao.updateByKey(stock);
        } finally {
            zkLockService.unLock(mutex);
        }
    }


    /**
     * zookeeper 实现锁
     */
    public void updateByKey4(Stock stock) throws Exception {
        ZkMutexLock zkMutexLock = null;
        try {
            zkMutexLock = new ZkMutexLock("myLock", curatorFramework);
            zkMutexLock.tryLock();
            Stock stock1 = stockDao.getByKey(stock.getId());
            if (stock1 == null) {
                System.out.println("商品不存在,id=" + stock.getId());
            }
            System.out.println("当前库存：num=" + stock1.getNum());

            stock.setNum(stock1.getNum() - 1);
            stockDao.updateByKey(stock);
        } finally {
            if (zkMutexLock != null) {
                zkMutexLock.unlock();
            }
        }
    }

    /**
     * redisson 锁
     */
    public void updateByKey5(Stock stock) throws Exception {
        RLock rLock = null;
        try {
            rLock = redissonClient.getLock(stock.getId() + "");
            rLock.lock();
            Stock stock1 = stockDao.getByKey(stock.getId());
            if (stock1 == null) {
                System.out.println("商品不存在,id=" + stock.getId());
            }
            System.out.println("当前库存：num=" + stock1.getNum());

            stock.setNum(stock1.getNum() - 1);
            stockDao.updateByKey(stock);

        } finally {
            if (rLock != null) {
                rLock.unlock();
            }
        }
    }

    /**
     * redis注解锁
     */
    @RedisLock(fieldName = "stock.id")
    public void updateByKey6(Stock stock) throws Exception {
        this.updateByKey(stock);
    }

    /**
     * mysql注解锁
     */
    @MySqlLock(fieldName = "stock.id")
    public void updateByKey7(Stock stock) throws Exception {
        this.updateByKey(stock);
    }

    /**
     * zookeeper注解锁
     */
    @ZooKeeperLock(fieldName = "stock.id")
    public void updateByKey8(Stock stock) throws Exception {
        this.updateByKey(stock);
    }

}
